package {{package}};

import io.helidon.http.HeaderNames;
import io.helidon.config.Config;
import io.helidon.cors.CrossOriginConfig;
import io.helidon.microprofile.testing.junit5.HelidonTest;
import jakarta.inject.Inject;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;

@HelidonTest
class TestCORS {

    @Inject
    private WebTarget target;

    @Test
    void testAnonymousGreetWithCors() {
        Response r = target.path("/simple-greet")
                .request()
                .header(HeaderNames.ORIGIN.defaultCase(), "http://foo.com")
                .header(HeaderNames.HOST.defaultCase(), "here.com")
                .get();

        assertThat("HTTP response", r.getStatus(), is(200));
        String payload = fromPayload(r);
        assertThat("HTTP response payload", payload.contains("Hello World!"), is(true));
        assertThat("CORS header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN,
                r.getHeaders().getFirst(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.defaultCase()),
                is("http://foo.com"));
    }

    @Test
    void testCustomGreetingWithCors() {
        Response r = target.path("/simple-greet")
                .request()
                .header(HeaderNames.ORIGIN.defaultCase(), "http://foo.com")
                .header(HeaderNames.HOST.defaultCase(), "here.com")
                .header("Access-Control-Request-Method", "PUT")
                .options();

        assertThat("pre-flight status", r.getStatus(), is(200));
        MultivaluedMap<String, Object> responseHeaders = r.getHeaders();
        assertThat("Header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_METHODS,
                r.getHeaders().getFirst(HeaderNames.ACCESS_CONTROL_ALLOW_METHODS.defaultCase()),
                is("PUT"));
        assertThat( "Header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN,
                r.getHeaders().getFirst(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.defaultCase()),
                is("http://foo.com"));

        Invocation.Builder builder = target.path("/simple-greet")
                .request()
                .headers(responseHeaders)
                .header(HeaderNames.ORIGIN.defaultCase(), "http://foo.com")
                .header(HeaderNames.HOST.defaultCase(), "here.com");

        r = putResponse("Cheers", builder);
        assertThat("HTTP response3", r.getStatus(), is(200));
        assertThat( "Header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN,
                r.getHeaders().getFirst(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.defaultCase()),
                is("http://foo.com"));
        assertThat(fromPayload(r), containsString("Cheers World!"));
    }

    @Test
    void testGreetingChangeWithCorsAndOtherOrigin() {
        Invocation.Builder builder = target.path("/simple-greet")
                .request()
                .header(HeaderNames.ORIGIN.defaultCase(), "http://other.com")
                .header(HeaderNames.HOST.defaultCase(), "here.com");

        Response r = putResponse("Ahoy", builder);
        boolean isOverriding = Config.global().get("cors").exists();
        assertThat("HTTP response3", r.getStatus(), is(isOverriding ? 204 : 403));
    }

    private static String fromPayload(Response response) {
        return response.readEntity(String.class);
    }

    private static Response putResponse(String message, Invocation.Builder builder) {
        return builder.put(Entity.entity(message, MediaType.TEXT_PLAIN_TYPE));
    }
}
